#ifndef _LVMAT_H_
#define _LVMAT_H_

#include <opencv2/highgui/highgui.hpp>
#include <memory>
#include <string>
#include <stdexcept>
#include <fstream>
// #include <iostream>

#define CHECK   if(m_mat == nullptr) throw std::logic_error("mat is null");

namespace lv::lvmat
{

class LvMat
{
public:
    LvMat();
    LvMat(size_t row, size_t col, int type);
    LvMat(const LvMat & src);
    LvMat(const LvMat && src);
    ~LvMat();

    size_t row();
    size_t col();
    template<class T>
    void set(size_t row, size_t col, T src);
    template<class T>
    T get(size_t row, size_t col);
    void hflip();
    void vflip();
    template<class T>
    void saveData(const std::string & fileName);
    
    LvMat & operator = (const LvMat & src);
    LvMat & operator = (const LvMat && src);
    friend std::ostream & operator << (std::ostream & out, LvMat & src);

    static void savePNG(const std::string & fileName, const cv::Mat & src);    // save RGB

public:
    uint8_t                             dataLength;

private:
    std::unique_ptr<cv::Mat>            m_mat           = nullptr;
};

template<class T>
void LvMat::set(size_t row, size_t col, T src)
{
    CHECK
    dataLength = sizeof(T);
    m_mat->at<T>(row, col) = src;
}

template<class T>
T LvMat::get(size_t row, size_t col)
{
    CHECK
    return m_mat->at<T>(row, col);
}   

template<class T>
void LvMat::saveData(const std::string & fileName)
{
    CHECK
    std::fstream out(fileName, std::ios_base::out);
    for(int i = 0; i < m_mat->rows; i++)
    {
        for(int j = 0; j < m_mat->cols; j++)
        {
            if(j != 0) out << ", ";
            if(dataLength == 1)
            {
                out << (uint16_t)m_mat->at<T>(i, j);
            }
            else
            {
                out << m_mat->at<T>(i, j);
            }
        }
        out << "\n";
    }
    out.close();
}


}



#endif